#ifndef _CRAB_TYPES_H__INCLUDED_
#define _CRAB_TYPES_H__INCLUDED_

#ifdef _MSC_VER
#pragma once
#endif // _MSC_VER

#include <base/lang/crab_platform.h>

#if defined(CRAB_OS_WIN32) && defined(CRAB_COMPILER_MSVC)
#   include <base/lang/crab_win32.h>
#elif defined(CRAB_OS_LINUX) && defined(CRAB_COMPILER_GCC)
#   include <base/lang/crab_linux.h>
#else
#   error please 
#endif

// standard c library includes
#include /**/ <cstdarg>
#include /**/ <cassert>
#include /**/ <climits>
#include /**/ <cerrno>
#include /**/ <ctime>
#include /**/ <cstdlib>
#include /**/ <cstdio>
#include /**/ <cctype>
#include /**/ <cstring>
#include /**/ <fcntl.h>
#include /**/ <malloc.h>

// default call convention
#ifndef CRAB_STDCALL
#   define CRAB_STDCALL CRAB_STDCALL
#endif

#ifndef CRAB_MIN
#   define CRAB_MIN(a, b) ((a) < (b) ? (a) : (b))
#endif

#ifndef CRAB_MAX
#   define CRAB_MAX(a, b) ((a) > (b) ? (a) : (b))
#endif

// assert
#if defined(CRAB_COMPILER_MSVC)
#   include <crtdbg.h>
#   define CRAB_ASSERT(a) _ASSERTE(a)
#else
#   define CRAB_ASSERT(a) assert(a)
#endif

#define CRAB_STATIC_ASSERT(ex, msg) \
    struct __crab_##msg { unsigned int msg : ex; };

// Typedefs for all primitive data type
typedef unsigned char     crab_u8_t;
typedef signed char       crab_i8_t;
typedef unsigned short    crab_u16_t;
typedef short             crab_i16_t;
typedef unsigned          crab_u32_t;
typedef int               crab_i32_t;

#ifdef CRAB_OS_WIN32
typedef __int64           crab_i64_t;
typedef unsigned __int64  crab_u64_t;
#else
typedef long long         crab_i64_t;
typedef unsigned long long crab_u64_t;
#endif

typedef crab_i8_t           crab_char_t;
typedef crab_i16_t          crab_wchar_t;
typedef crab_u8_t           crab_byte_t;

// ensure primitive data types is of expected size
CRAB_STATIC_ASSERT(sizeof(crab_u8_t) == 1, crab_u8_t_is_not_1_bytes);
CRAB_STATIC_ASSERT(sizeof(crab_i8_t) == 1, crab_i8_t_is_not_2_bytes);
CRAB_STATIC_ASSERT(sizeof(crab_u16_t) == 2, crab_u16_t_is_not_2_bytes);
CRAB_STATIC_ASSERT(sizeof(crab_i16_t) == 2, crab_i16_t_is_not_2_bytes);
CRAB_STATIC_ASSERT(sizeof(crab_u32_t) == 4, crab_u32_t_is_not_4_bytes);
CRAB_STATIC_ASSERT(sizeof(crab_i32_t) == 4, crab_i32_t_is_not_4_bytes);
CRAB_STATIC_ASSERT(sizeof(crab_u64_t) == 8, crab_u64_t_is_not_8_bytes);
CRAB_STATIC_ASSERT(sizeof(crab_i64_t) == 8, crab_i64_t_is_not_8_bytes);
CRAB_STATIC_ASSERT(sizeof(float) == 4, float_is_not_4_bytes);
CRAB_STATIC_ASSERT(sizeof(double) == 8, double_is_not_8_bytes);
CRAB_STATIC_ASSERT(sizeof(time_t) == 4, time_t_is_not_4_bytes);

#ifndef CRAB_FALSE
#   define CRAB_TRUE  (1 == 1)
#   define CRAB_FALSE (1 == 0)
#endif

#if defined(CRAB_OS_WIN32)
    typedef DWORD   crab_threadid_t;
    typedef HANDLE  crab_threadhandle_t;
    typedef HANDLE  crab_handle_t;
#elif defined(CRAB_OS_LINUX)
    typedef pthread_t  crab_threadid_t;
    typedef pthread_t  crab_threadhandle_t;
    typedef void*      crab_handle_t;
#else
#   error please todo...
#endif

#define CRAB_UNUSED_ARG(x) if(&x) {}

// imports/GS_OS_WIN32
#ifdef CRAB_COMMON_BUILD_DLL
#   define CRAB_COMMON_EXPORT CRAB_EXPORT_DECL
#else
#   define CRAB_COMMON_EXPORT CRAB_IMPORT_DECL
#endif

#define CRAB_LANG_NS crab::lang

#define CRAB_LANG_NS_STR "crab::lang"

// namespace crab {
#define CRAB_LANG_BEGIN_NAMESPACE() namespace crab{ namespace lang{

// } /*namespace*/
#define CRAB_LANG_END_NAMESPACE() }}

#endif /*_CRAB_TYPES_H__INCLUDED_*/
